
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using MUSA;
#endregion

namespace MUSA
{
    /// <summary>
    /// Static or Dynamic
    /// </summary>
    public enum ObjectType
    {
        STATIC ,
        DYNAMIC
    }

    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public abstract partial class Object : Microsoft.Xna.Framework.GameComponent
    {
        #region Member Variables

        protected MModel objectModel;

        protected Vector3 position;

        protected ObjectType mType;
        protected bool collide = false;

        protected Game mGame = null;

        #endregion

        #region Properties

        public ObjectType Type
        {
            get
            {
                return mType;
            }
        }

        public Vector3 Position
        {
            get
            {
                return position;
            }

            set
            {
                position = value;
            }
        }

        #endregion

        #region Constructor
        public Object(Game game)
            : base(game)
        {
            // TODO: Construct any child components here

            mGame = game;

            Create();
        }
        #endregion

        #region GameComponent Methods
        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here
            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here

            base.Update(gameTime);
        }

        #endregion

        #region Public Methods

        public abstract bool Collide(BoundingBox pBox);

        public abstract bool Collide(BoundingSphere pSphere);

        public abstract void Draw(GameTime gTime);

        #endregion

        #region Protected Methods

        protected abstract void Create();

        #endregion
    }

    public class MModel
    {
        #region Member Variables

        Model model;

        Vector3 position;       //position in world
        Vector3 direction;      //facing direction

        Color mColor;

        Matrix worldMatrix;     //transform matrix

        #endregion

        #region Properties

        public Vector3 POSITION
        {
            set
            {
                position = value;
            }
        }

        public Vector3 DIRECTION
        {
            set
            {
                direction = value;
            }
        }

        public Model MODEL
        {
            get
            {
                return model;
            }
        }

        public Color COLOR
        {
            set
            {
                mColor = value;
            }
        }

        #endregion

        #region Constructor

        public MModel(string asset, Vector3 _position, Vector3 _direction)
        {
            model = MUSA.mContentManager.Load<Model>(asset);
            position = _position;
            direction = _direction;

            mColor = Color.Gray;

            GenerateWorldTransforms();
        }

        #endregion

        #region Methods

        private void GenerateWorldTransforms()
        {
            float tang;     //transformation angle of rotation

            //get angle of direction against the vector (1, 0)
            tang = (float)(Math.Atan2(direction.Y, direction.X) - Math.Atan2(0, 1));

            //calculate model transformation
            worldMatrix = Matrix.Multiply(Matrix.CreateRotationZ(tang), Matrix.CreateTranslation(position));
        }

        public void Update(GameTime gtime)
        {
            GenerateWorldTransforms();
        }

        public void Draw()
        {
            foreach (ModelMesh m in model.Meshes)
            {
                foreach (BasicEffect be in m.Effects)
                {
                    be.EnableDefaultLighting();
                    be.DiffuseColor = new Vector3(mColor.R / 256f, mColor.G / 256f, mColor.B / 256f);

                    be.World = worldMatrix;
                    be.Projection = MUSA.mCamera.Projection;
                    be.View = MUSA.mCamera.View;
                }

                m.Draw();
            }
        }

        #endregion
    }
}
